//Source code for Triangle's and associated functions
#include "Geometry.h"

Triangle::Triangle()
{
	v0 = v1 = v2 = normal = Vector3(0.0f, 0.0f, 0.0f);
}

//Initialization of triangle
Triangle::Triangle(const Vector3& _v0, const Vector3& _v1, const Vector3& _v2)
{
	v0 = _v0;
	v1 = _v1;
	v2 = _v2;
	normal = (v1-v0) ^ (v2-v0);
	normal.Normalize();
}

// We have implemented using Cramer's rule
// But Moller-Trumbore method is more efficient
// We will implement it later
bool Triangle::IntersectionTest(Ray3& ray, float tmin, float tmax, IntersectionPacket& pkt)
{
	
	float beta, gamma, t;		//barycentric coords and distance from ray(solution)
	float A,B,C,D,E,F,G,H,I,J,K,L;

	A = v0.x - v1.x; B = v0.y - v1.y; C = v0.z - v1.z;
	D = v0.x - v2.x; E = v0.y - v2.y; F = v0.z - v2.z;
	G = ray.direction.x; H = ray.direction.y; I = ray.direction.z;
	J = v0.x - ray.origin.x; K = v0.y - ray.origin.y; L = v0.z - ray.origin.z;

	float determinant = A*(E*I-H*F) + B*(G*F-D*I) + C*(D*H-E*G);

	if(determinant == 0.0f) return false;		//no solution
	else
	{
		//find beta
		beta = (J*(E*I-H*F) + K*(G*F-D*I) + L*(D*H-E*G))/determinant;
		if(beta < 0.0f || beta > 1.0f) return false; //as beta + gamma = 1 is max value

		//find gamma
		gamma = (I*(A*K-J*B) + H*(J*C-A*L) + G*(B*L-K*C))/determinant;
		if(gamma < 0.0f || gamma > 1.0f || (beta + gamma > 1.0f)) return false;

		//now find t
		t = - ((F*(A*K-J*B) + E*(J*C-A*L) + D*(B*L-K*C))/determinant);
		if(t <= 0.0f) return false;		//we dont want a negative ray .. add tmin values later
		else
		{
			pkt.t = t;
			return true;
		}
	}
}

//Shadow ray intersection test
bool Triangle::ShadowRayTest(Ray3& ray, float tmin, float tmax)
{
	float beta, gamma, t;		//barycentric coords and distance from ray(solution)
	float A,B,C,D,E,F,G,H,I,J,K,L;

	A = v0.x - v1.x; B = v0.y - v1.y; C = v0.z - v1.z;
	D = v0.x - v2.x; E = v0.y - v2.y; F = v0.z - v2.z;
	G = ray.direction.x; H = ray.direction.y; I = ray.direction.z;
	J = v0.x - ray.origin.x; K = v0.y - ray.origin.y; L = v0.z - ray.origin.z;

	float determinant = A*(E*I-H*F) + B*(G*F-D*I) + C*(D*H-E*G);

	if(determinant <= 0.0f) return false;		//no solution
	else
	{
		//find beta
		beta = (J*(E*I-H*F) + K*(G*F-D*I) + L*(D*H-E*G))/determinant;
		if(beta < 0.0f || beta > 1.0f) return false; //as beta + gamma = 1 is max value

		//find gamma
		gamma = (I*(A*K-J*B) + H*(J*C-A*L) + G*(B*L-K*C))/determinant;
		if(gamma > 1.0f || (beta + gamma > 1.0f)) return false;

		//now find t
		t = - ((F*(A*K-J*B) + E*(J*C-A*L) + D*(B*L-K*C))/determinant);
		if(t <= 0.0f) return false;		//we dont want a negative ray .. add tmin values later
		else return true;		//yes shadow ray hits this.
	}

}
